<?php
/**
 * Created by PhpStorm.
 * User: chniccs
 * Date: 2019-12-13
 * Time: 10:26
 */

namespace app\helper;


use app\constant\EsConst;
use Elasticsearch\ClientBuilder;

class EsHelper
{
    private $client;
    const OK=200;

    public function __construct()
    {
        $hosts = ['111.229.34.187:9200'];
        $this->client = ClientBuilder::create()
            ->setHosts($hosts)
            ->build();
    }

    /**
     * 添加一些默认参数
     * @param $params
     * @return mixed
     */
    private function paramsSetting($params)
    {
        //忽略400和404错误
        if (empty($params['client']['ignore'])) {
            $params['client']['ignore'] = [400, 404, 405];
        }
        //返回数据时顺带code值等
        if (empty($params['client']['verbose'])) {
            $params['client']['verbose'] = true;
        }
        if (empty($params['client']['timeout'])) {
            $params['client']['timeout'] = 20;
        }
        if (empty($params['client']['connect_timeout'])) {
            $params['client']['connect_timeout'] = 20;
        }
        // if (empty($params['client']['future'])){
        //  $params['client']['future'] = 'lazy';
        // }
        return $params;
    }


    /**
     * 创建索引
     * @param $index String 索引名称 建议：项目+日期(年月)
     * @param $body array|null 索引参数 可空
     * @return array|callable
     */
    public function createIndex($index = EsConst::INDEX_TYPE, $body = null)
    {
        //判断索引是否已存在
        $currentIndex = $this->getIndexs([$index]);
        if ($currentIndex['code'] == 'SUCCESS') {
            return ['code' => 'FAIL', 'msg' => '索引已存在'];
        }
        if ($body == null) {
            $body = [
                'settings' => [
                    'number_of_shards' => 5,
                    'number_of_replicas' => 0
                ]
            ];
        }
        $params = [
            'index' => $index,
            'body' => $body
        ];
        $params = $this->paramsSetting($params);
        $result = $this->client->indices()->create($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status']];
        }
    }

    /**
     * 获取索引配置
     * @param $indexs ['index1', 'index2', ...]
     * @return array|callable
     */
    public function getIndexs($indexs)
    {
        $params = [
            'index' => $indexs
        ];
        $params = $this->paramsSetting($params);
        $result = $this->client->indices()->getSettings($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }

    /**
     * 修改索引配置
     * @param $index
     * @param string $body
     * @return array|callable
     */
    public function updateIndex($index, $settings)
    {
        //判断索引是否已存在
        $currentIndex = $this->getIndexs([$index]);
        if ($currentIndex['status'] != self::OK) {
            return ['code' => 'FAIL', 'msg' => '索引不存在'];
        }
        $body = '';
        if (count($settings) > 0) {
            $body = ['settings' => $settings];
        } else {
            return ['code' => 'FAIL', 'msg' => '未提供修改信息！'];
        }
        $params = [
            'index' => $index,
            'body' => $body
        ];
        $params = $this->paramsSetting($params);

        $result = $this->client->indices()->putSettings($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }

    /**
     * 删除索引
     * @param $index
     * @return array|callable
     */
    public function deleteIndex($index)
    {
        $params = [
            'index' => $index
        ];
        $params = $this->paramsSetting($params);
        $result = $this->client->indices()->delete($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }

    /**
     * 索引文档
     * @param $index String
     * @param $type
     * @param $id 可不传递，会自动生成
     * @param $body ['field1' => '1', 'field2' => '2', ...]
     * @return array|callable
     */
    public function indexSingleDoc($index = EsConst::INDEX_TYPE, $type, $id = '', $body)
    {
        $params = [
            'index' => $index,
            'type' => $type,
            'body' => $body,
            'id' => $id
        ];
        $params = $this->paramsSetting($params);
        $result = $this->client->index($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }


    /**
     * 批量索引文档
     * @param $index
     * @param $type
     * @param $docs [['id' => '', 'body' => ['field1' => '1', 'field2' => '2', ...]], ['id' => '', 'body' => ['field1' => '1', 'field2' => '2', ...]], ...]
     * @return array
     */
    public function indexMultiDoc($index, $type, $docs)
    {
        $params = ['body' => []];
        foreach ($docs as $doc) {
            $params['body'][] = [
                'index' => [
                    '_index' => $index,
                    '_type' => $type,
                    '_id' => $doc['id'] ? $doc['id'] : ''
                ]
            ];
            $params['body'][] = $doc['body'];

            if (count($params['body']) % 1000 == 0) {
                $params = $this->paramsSetting($params);
                $responses = $this->client->bulk($params);
                if ($responses['status'] != self::OK) {
                    return ['code' => 'Fail', 'msg' => '索引文档失败！'];
                }
                $params = ['body' => []];
                unset($responses);
            }
        }
        if (!empty($params['body'])) {
            $params = $this->paramsSetting($params);
            $responses = $this->client->bulk($params);
            if ($responses['status'] != self::OK) {
                return ['code' => 'Fail', 'msg' => '索引文档失败！'];
            }
        }
        return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => '索引文档成功！'];
    }

    /**
     * 获取文档 参数不可为空
     * @param $index
     * @param $type
     * @param $id
     * @return array|callable
     */
    public function getDoc($index, $type, $id)
    {
        $params = [
            'index' => $index,
            'type' => $type,
            'id' => $id
        ];
        $params = $this->paramsSetting($params);
        $result = $this->client->get($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }

    /**
     * 更新文档
     * https://www.elastic.co/guide/cn/elasticsearch/php/current/_updating_documents.html#_script_更新
     * @param $title
     * @param $type
     * @param $id
     * @param $body
     *  部分更新 $body = ['doc' => ['field1' => 'new value', 'field2' => 'new value', 'field3' => 'new value']]
     *  script更新 $body = ['script' => 'ctx._source.counter += count', 'params' => ['count' => 4]]
     *  upsert更新 $body = ['script' => 'ctx._source.counter += count', 'params' => ['count' => 4], 'upsert' => ['counter' => 1]]
     * @return array|callable
     */
    public function updateDoc($index, $type, $id, $body)
    {
        $params = [
            'index' => $index,
            'type' => $type,
            'id' => $id,
            'body' => $body
        ];
        $params = $this->paramsSetting($params);
        $result = $this->client->update($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }

    /**
     * 删除文档
     * @param $title
     * @param $type
     * @param $id
     * @return array|callable
     */
    public function deleteDoc($index, $type, $id)
    {
        $params = [
            'index' => $index,
            'type' => $type,
            'id' => $id
        ];
        $params = $this->paramsSetting($params);
        $result = $this->client->delete($params);
        if ($result['status'] == self::OK) {
            return ['code' => 'SUCCESS', 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => 'FAIL', 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }


    //查询
    public function search($index, $type, $body)
    {
        $params = [
            'index' => $index,
            'type' => $type,
            'body' => $body
        ];
        $params = $this->paramsSetting($params);
        // dd(json_encode($params));
        $result = $this->client->search($params);
        // dd(json_encode($result));
        if ($result['status'] == self::OK) {
            return ['code' => true, 'msg' => 'es执行成功！', 'content' => $result['body']];
        } else {
            return ['code' => false, 'msg' => '错误码：' . $result['status'] . ' 错误信息：' . $result['body']['error']['reason']];
        }
    }

}